﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;

namespace MvePublicService
{
	/*
	 * 日本SGI株式会社
	 * ヨハンソン・ヘンリク
	 * johansson@sgi.co.jp
	 * 
	 * Change Log:
	 * ---------------------------------------------------------------------------
	 * 2009.01.07	Johansson Henrik		Class Created.
	 * 2008.01.08							Changed Access Modifier of _loggedInUsers 
	 *										to Internal
	 */

	/// <summary>
	/// This static class provides methods to verify user credentials
	/// in the Database, logging in and logging out users from the Service,
	/// and other operations that deal with users of the Service.
	/// Use the static methods in this class to perform  
	/// User related operations in the Service.
	/// </summary>
	/// <remarks>INSERT:Creds</remarks>
	internal static class UserManager
	{
		/// <summary>
		/// Defines how long the user's login is valid in the Service.
		/// </summary>
		public static double ValidLoginPeriodInHours { get; set; }

		/// <summary>
		/// Holds a list of all the currently logged in users.
		/// </summary>
		internal static Dictionary<Guid, UserDataObject> _loggedInUsers
			= new Dictionary<Guid, UserDataObject>();

		/// <summary>
		/// Verify a Username/Password pair agains the member table and get the 
		/// Database Id of the verified user.
		/// </summary>
		/// <remarks>Done</remarks>
		/// <param name="userName">Username to verify</param>
		/// <param name="password">Password to verify</param>
		/// <param name="userDbId">An Int to hold the Database Id of the verified user</param>
		/// <param name="connection">Sql Connection</param>
		/// <returns>True if the Credentials where verified</returns>
		public static bool VerifyUserCredentials(
			string userName, string password, ref int? userDbId, SqlConnection connection)
		{
			SqlCommand command = new SqlCommand();
			command.CommandTimeout = 60;
			bool result = false;

			try
			{
				command.Connection = connection;
				command.CommandType = System.Data.CommandType.StoredProcedure;
				command.CommandText = "VerifyUserCredentials";

				command.Parameters.Add("name", SqlDbType.VarChar, 32);
				command.Parameters.Add("password", SqlDbType.VarChar, 13);
				command.Parameters[0].Value = userName;
				command.Parameters[1].Value = password;

				SqlParameter pmId = new SqlParameter("databaseId", SqlDbType.Int);
				pmId.Direction = ParameterDirection.Output;
				command.Parameters.Insert(2, pmId);

				SqlParameter returnValue = new SqlParameter("@RETURN_VALUE", SqlDbType.Int);
				returnValue.Direction = ParameterDirection.ReturnValue;
				command.Parameters.Add(returnValue);

				command.ExecuteNonQuery();
				int resultCode = (int)returnValue.Value;

				if (resultCode == 0)
				{
					userDbId = (int)pmId.Value;
					result = true;
				}
				else
					result = false;
			}
			catch (InvalidOperationException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = false;
			}
			catch (InvalidCastException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = false;
			}
			finally
			{
				command.Dispose();
			}

			return result;
		}//end:VerifyUserCredentials

		/// <summary>
		/// Gets the UserDbId associated with a UserServiceId.
		/// <remarks>Done</remarks>
		/// </summary>
		public static void GetUserDbIdFromUserServiceId(Guid userServiceId, ref int? userDbId)
		{
			try
			{
				userDbId = UserManager._loggedInUsers[userServiceId].userDbId;
				return;
			}
			catch (KeyNotFoundException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				return;
			}
		}//end:GetUserDbIdFromUserServiceId

		/// <summary>
		/// Verify that the UserServiceId is really logged in.
		/// </summary>
		/// <remarks>Done</remarks>
		/// <returns>True if the UserServiceId exists in the pool of logged in users.</returns>
		public static bool VerifyLoggedInUserRecord(Guid userServiceId)
		{
			try
			{
				//TODO:Determine default valid period
				if (UserManager.ValidLoginPeriodInHours == 0)
					ValidLoginPeriodInHours = 12;

				if (UserManager._loggedInUsers.ContainsKey(userServiceId))
				{
					DateTime loginTime = UserManager._loggedInUsers[userServiceId].userLogonTimestamp;
					DateTime loginTimeExpires = loginTime.AddHours(UserManager.ValidLoginPeriodInHours);
					if (loginTimeExpires.CompareTo(DateTime.Now) < 0)
					{
						//The session has expired
						return false;
					}
					else
						return true;
				}
				else
					return false;

			}
			catch (NullReferenceException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				return false;
			}
		}//end:VerifyLoggedInUserRecord

		/// <summary>
		/// Register a logged in UserDbId to the pool of logged in users, and retrieve
		/// a UserServiceId for the UserDbId.
		/// </summary>
		/// <remarks>Done</remarks>
		/// <returns>A new UserServiceId associated with the provided UserDbId.</returns>
		public static Guid RegisterUserLogin(string userName, int userDbId)
		{
			UserDataObject user = new UserDataObject()
			{
				userDbId = userDbId,
				userName = userName,
				userLogonTimestamp = DateTime.Now
			};

			//Make really sure we are not trying to register the same
			//GUID for two different users.
			Guid t_UserID = Guid.NewGuid();
			int tries = 0;
			while (UserManager._loggedInUsers.ContainsKey(t_UserID))
			{
				//Prevent Never Ending Loop
				if (tries >= 100)
					break;

				t_UserID = Guid.NewGuid();

				tries += 1;
			}

			user.userServiceId = t_UserID;

			UserManager._loggedInUsers.Add(user.userServiceId, user);

			return user.userServiceId;
		}//end:RegisterUserLogin

		/// <summary>
		/// Remove a UserServiceId from the pool of logged in users.
		/// </summary>
		/// <remarks>Done</remarks>
		/// <returns>True if the UserServiceId existed AND was removed from the pool.</returns>
		public static bool RegisterUserLogoff(Guid userServiceId)
		{
			if (UserManager._loggedInUsers.ContainsKey(userServiceId))
			{
				UserManager._loggedInUsers.Remove(userServiceId);
				return true;
			}
			else
				return false;
		}//end:RegisterUserLogoff


		/*
		 * 日本SGI株式会社
		 * ヨハンソン・ヘンリク
		 * johansson@sgi.co.jp
		 * 
		 * Change Log:
		 * ---------------------------------------------------------------------------
		 * 2009.01.07	Johansson Henrik		Class Created.
		 * 2008.01.08	Johansson Henrik		Changed Access Modifier to Internal
		 */

		/// <summary>
		/// Represents a Service User object.
		/// </summary>
		internal class UserDataObject
		{
			public int userDbId { get; set; }
			public Guid userServiceId { get; set; }
			public string userName { get; set; }
			public DateTime userLogonTimestamp { get; set; }
		}
	}
}
